<?php

abstract class IController extends IObject {
	/**
	 * Enter description here...
	 *
	 * @var IAction
	 */
	private $action;
	private $params = array();
	private $filters = array();
	private static $controllerKeyword = "controller";
	private static $actionKeyword = "action";
	private static $defaultAction = "index";	
	/**
	 * Enter description here...
	 *
	 * @var IRouter
	 */
	private $router;
	private $name;
	
	/**
	 * Enter description here...
	 *
	 * @var IContext
	 */
	protected $context;
	
	/**
	 * Enter description here...
	 *
	 * @var ILocale
	 */
	protected $locale;
	
	public final function __construct() {
		//检查IApplication是否启动
		if(!IApplication::started()) {
			IApplication::start(false);
		}
		
		$this->context = IContext::singleton();
		$this->locale = $this->locale();
		
		//过滤器
		$filters = IConfig::opt("@controller.filters");
		if (is_array($filters)) {
			$this->filters = $filters;
		}
	}
	
	public function setAction($action) {
		$this->action = new IAction($action);
	}
	
	/**
	 * Enter description here...
	 *
	 * @return IContext
	 */
	public final function context() {
		return IContext::singleton();
	}
	
	/**
	 * Enter description here...
	 *
	 * @return IAction
	 */
	public function action() {
		if ($this->action == null) {
			$action = $this->context()->request()->param(self::$actionKeyword);
			if ($action != null) {
				$this->action = new IAction($action);
			}
			else {
				$this->action = new IAction(self::$defaultAction);
			}
		}
		return $this->action;
	}
	
	public function addParams(array $params) {
		$this->params = array_merge($this->params, $params);
	}
	
	public function addParam($param, $value) {
		$this->params[$param] = $value;
	}
	
	public function param($name) {
		return array_key_exists($name, $this->params)?$this->params[$name]:null;
	}
	
	public function params() {
		return $this->params;
	}
	
	public function addFilter($filter, $actions = null) {
		if (!is_subclass_of($filter, "IActionFilter")) {
			throw new IException("action filter '{$filter}' must be inherited from IActionFilter", IF_EXCEPTION_1001, IF_MODULE_CONTROLLER);
		}
		if ($actions == null) {
			$actions = "*";
		}
		$this->filters[] = array("filter" => $filter, "actions" => $actions);
	}
	
	private function filtersByAction($action) {
		$filters = array();
		foreach ($this->filters as $filter) {
			if ($this->action->match($filter["actions"])) {
				$filterClass = $filter["filter"];
				$filters[] = $filterClass;
			}
		}
		return $filters;
	}
	
	public function exec() {		
		//检查action是否存在
		$this->action = $this->action();
		$controller = get_class($this);
		$actionName = $this->action->name();
		$method = $this->action->method();//action对应的方法
		if (!method_exists($this, $method)) {
			throw new IException("can't find action '{$actionName}' in controller '{$controller}'");
		}
		
		//处理特殊属性
		
		
		//执行_init/_before
		$this->_init();
		$this->_before();
		
		//过滤器
		$filters = $this->filtersByAction($this->action);
		foreach ($filters as $filter) {
			$filterObj = IRegistry::singleton()->single($filter);
			if ($filterObj->before($this) === false) {
				return;
			}
		}
		
		//将$filters的顺序倒置
		$filters = array_reverse($filters);
		
		//执行action
		$reflect = new IReflection($controller);
		$ret = $reflect->invoke($this, $method);
		$this->action->setRet($ret);
		
		//过滤器
		$filters = $this->filtersByAction($this->action);
		foreach ($filters as $filter) {
			$filterObj = IRegistry::singleton()->single($filter);
			if ($filterObj->after($this) === false) {
				return;
			}
		}
		
		//执行_after
		$this->_after();
	}
	
	public static function setControllerKeyword($controllerKeyword) {
		self::$controllerKeyword = $controllerKeyword;
	}
	
	public static function setActionKeyword($actionKeyword) {
		self::$actionKeyword = $actionKeyword;
	}
	
	public static function controllerKeyword() {
		return self::$controllerKeyword;
	}
	
	public static function actionKeyword() {
		return self::$actionKeyword;
	}
	
	public static function setDefaultAction($default) {
		self::$defaultAction = $default;
	}
	
	public static function defaultAction() {
		return self::$defaultAction;
	}
	
	public static function findByName($name) {
		$pieces = explode(".", $name);
		$useful = array();
		if (empty($pieces)) {
			return null;
		}
		$controller = array_pop($pieces);
		$class = ucfirst($controller) . "Controller";
		foreach ($pieces as $piece) {
			if (!preg_match("/^[\\w\\-]+$/", $piece)) {
				return null;
			}
			$useful[] = $piece;
		}
		if (!empty($useful)) {
			$class = implode(".", $useful) . "." . $class;
		}
		return $class;
	}
	
	/**
	 * Enter description here...
	 *
	 * @param unknown_type $name
	 * @return IController
	 */
	public static function objByName($name) {
		$obj = null;
		try {
			$obj = IRegistry::singleton()->single(self::findByName($name));
		} catch (IException $e) {
			
		}
		return $obj;
	}
	
	public function setRouter(IRouter $router) {
		$this->router = $router;
	}
	
	public function setName($name) {
		$this->name = $name;
	}
	
	public function name() {
		return $this->name;
	}
	
	public function path($controllerOrActionName = null, $actionName = null) {
		$_controller = null;
		$_action = null;
		if ($controllerOrActionName == null) {
			$_controller = $this->name;
			if ($actionName == null) {
				$_action = $this->action->name();
			}
			else {
				$_action = $actionName;
			}
		}
		else {
			if ($actionName == null) {
				$_controller = $this->name;
				$_action = $controllerOrActionName;
			}
			else {
				$_controller = $controllerOrActionName;
				$_action = $actionName;
			}
		}
		return $this->router->path($_controller, $_action);
	}
	
	/**
	 * 调用未定义属性时激活的方法
	 * 
	 * 不允许子类覆写此方法
	 *
	 * @param string $varname 调用的属性名
	 * @return mixed
	 */
	public final function __get($varname) {
		try {
			return IReflection::property($this, $varname);
		}
		catch (IException $e) {
			if (IApplication::hasModule("activerecord") && preg_match("/^(.+)Query$/i", $varname, $match)) {
				return IDAO::query($match[1]);		
			}
			return $this->$varname = new IEmptyObject();
		}
	}
	
	/**
	 * 跳转到新的URL
	 *
	 * @param string $url URL
	 */
	public function redirectUrl($url) {
		IResponse::singleton()->redirect($url);
	}
	
		/**
	 * 跳转到新的action上
	 *
	 * @param string $controllerOrActionName 控制器或者action名称
	 * @param string $actionName action名称
	 * @since 0.0.3
	 */
	public function redirect($controllerOrActionName, $actionName = null, array $params = null) {
		$path = $this->getPath($controllerOrActionName, $actionName);
		if (is_array($params)) {
			$query = array();
			foreach ($params as $key=>$value) {
				$query[] = $key . "=" . urlencode($value);
			}
			if (!empty($params)) {
				$path .= "?" . implode("&", $query);
			}
		}
		$this->redirectUrl($path);
	}
	
		/**
	 * 在当前界面绘制新的action
	 * 
	 * 支持:
	 * - forward(action)
	 * - forward(controller, action)
	 *
	 * @param string $controllerOrActionName 控制器或者action名称
	 * @param string $actionName action名称
	 * @since 0.1
	 */
	public function forward($controllerOrActionName, $actionName = null, array $params = null) {
		if (is_null($controllerOrActionName) && is_null($actionName)) {
			return;
		}
		if (is_null($actionName)) {
			$controllerName = $this->name;
			$actionName = $controllerOrActionName;
		}
		else {
			$controllerName = $controllerOrActionName;
		}
		$controller = self::objByName($controllerName);
		$controller->setAction($actionName);
		if ($params != null) {
			$controller->addParams($params);
		}
		$controller->addParams($this->params);
		$controller->setRouter($this->router);
		$controller->setName($controllerName);
		$controller->exec();
	}
	
	protected function _before() {
		
	}
	
	protected function _after() {
		
	}
	
	protected function _init() {
		
	}
	
	public function locale() {
		if ($this->locale == null) {
			$this->locale = IApplication::singleton()->locale();
		}
		return $this->locale;
	}
	
	/**
	 * Enter description here...
	 *
	 * @return IRouter
	 */
	public function router() {
		return $this->router;
	}
}


?>